# gozerlib/eventbase.py
#
#

""" base class of all events. """

## gozerlib imports

from utils.lazydict import LazyDict
from utils.generic import splittxt
from less import Less

## simplejson imports

from waveapi.simplejson import dumps, loads, JSONDecodeError

## basic imports

import Queue
import copy
import types
import logging
import cgi
from  xml.sax.saxutils import unescape

cpy = copy.deepcopy

class EventBase(LazyDict):

    """ basic event class. """

    def __init__(self, input=None):
        LazyDict.__init__(self)
        self.bot = None
        self.type = "notset"
        self.cbtype = "notset"
        self.origin = ""
        self.cmnd = ""
        self.msg = True
        self.iscallback = False
        self.isgae = True
        self.iswave = False
        self.isweb = False
        self.isxmpp = False
        self.isremote = False
        self.ispoller = False
        self.properties = None
        self.remoteout = ""
        self.remotecmnd = False
        self.context = None
        self.request = None
        self.response = None
        self.auth = u""
        self.userhost = u""
        self.resource = u""
        self.channel = u""
        self.title = u""
        self.nick = u""
        self.origtxt = u""
        self.txt = u""
        self.args = []
        self.rest = u""
        self.queues = []
        self.inqueue = None
        self.aliased = False
        self.replied = False
        self.waveid = None

    def __deepcopy__(self, a):

        """ deepcopy an event. """

        e = EventBase()
        e.copyin(self)
        return e

    def _raw(self, txt):

        """ put rawstring to the server .. overload this """

        logging.warn(u"eventbase - out - %s - %s" % (self.userhost, unicode(txt)))
        print txt

    def parse(self, *args, **kwargs):

        """ overload this. """

        pass

    def copyin(self, eventin):

        """ 
            copy in an event.

            :param eventin: event to copy
            :type eventin: gozerlib.eventbase.EventBase
            :rtype: self

        """

        self.update(eventin)

        if eventin.has_key('queues'):
            self.queues = list(eventin.queues)

        #if eventin.has_key('inqueue'):
        #    self.inqueue = cpy(eventin.inqueue)

        return self

    def makeargs(self):

        """ make arguments and rest attributes from self.txt. """

        try:
            self.args = self.txt.split()[1:]
            self.rest = ' '.join(self.args)
        except:
            self.args = None

    def makeresponse(self, txt, result=[], nritems=False, dot=" .. ", *args, **kwargs):

        """ 
            create response. 

            :param txt: text prepended to result
            :type txt: string
            :param result:
            :type result: list of results (strings)
            :param nritems: whether items should be numbered (not used now)
            :type nritems: boolean
            :rtype: string

        """

        res = unicode(txt) 

        if result:


            if dot == True:
                dot = " .. "
               
            if type(result) == types.DictType:
                res += str(result) + ' .. '
            else:
                counter = 1

                for item in result:

                    if nritems:
                        res += str(counter) + u') ' + unicode(item)
                    else:
                        res += unicode(item)

                    if dot:
                        res += dot
                    else:
                        res += u' '

                    counter += 1

            if dot:
                res = res[:-len(dot)]
          
        return res
 
    def reply(self, txt, resultlist=[], nritems=False, dot=" .. ", escape=True, *args, **kwargs):

        """ 
             default reply .. OVERLOAD THIS .. defaults output to stdout.

            :param txt: text prepended to result
            :type txt: string
            :param result:
            :type result: list of results (strings)
            :param nritems: whether items should be numbered (not used now)
            :type nritems: boolean
            :rtype: string
        """

        if self.queues:
            for queue in self.queues:
                for result in resultlist:
                    queue.put_nowait(result)
            return

        result = self.makeresponse(txt, resultlist, nritems, dot, *args, **kwargs)
        (res, result) = self.less(result)
        print res
        print result
        return self

    def missing(self, txt):

        """ 
            display missing arguments. 

            :param txt: txt to display
            :type txt: string
            :rtype: None

        """

        if self.origtxt:
            splitted = self.origtxt.split()

            if self.bot.nick in splitted[0]:

                try:
                    cmnd = splitted[1]
                except IndexError:
                    cmnd = splitted[0]

            elif 'cmnd' in splitted[0]:

                try:
                    cmnd = splitted[2]
                except IndexError:
                    cmnd = splitted[0]

            else:

                if self.msg:
                    cmnd = splitted[0]
                else:
                    if self.aliased:
                        cmnd = self.aliased
                    else:
                        cmnd = splitted[0]

            self.reply(cmnd + ' ' + txt)

        else:
            self.reply('missing origtxt: %s' % txt)

    def checkqueues(self, resultlist):

        """ 
            check if resultlist is to be sent to the queues. if so do it

            :param resultlist: list of results to send to queues
            :type resultlist: list
            :rtype: boolean

        """

        if self.queues:

            for queue in self.queues:
                for item in resultlist:
                    queue.put_nowait(item)

            return True

        return False

    def done(self):

        """ tell the user we are done. """

        self.reply('done')


    def less(self, what, raw=False):
        """
            split up in parts of 1000 chars overflowing on word boundaries.
            put remaining txt into outcache.

            :param what: text to split
            :type what: string
            :rtype: list of 1st and second string to display

        """
        what = what.strip()
        txtlist = splittxt(what, 1000)
        size = 0

        # send first block
        res = txtlist[0]

        # see if we need to store output in less cache
        result = ""
        if len(txtlist) > 2:
            self.bot.outcache.add(self.userhost, txtlist[1:])
            size = len(txtlist) - 2
            result = txtlist[1:2][0]
            if size:
                result += " (+%s)" % size
        else:
            if len(txtlist) == 2:
                result = txtlist[1]

        return [res, result]

    def tojson(self):
        new = cpy(self)
        new.properties = 'setremote'
        new.context = 'setremote'
        new.request = 'setremote'
        new.response = 'setremote'
        new.doc = 'setremote'
        new.root = 'setremote'
        new.blip = 'setremote'
        new.blipcontext = 'setremote'
        new.child = 'setremote'
        new.sock = 'setremote'
        new.bot = 'setremote'
        new.queues = []
        logging.debug('eventbase - tojson - %s' % str(new))
        return dumps(new)

    def fromstring(self, input):  
        instr = unescape(input)

        try:
            temp = loads(instr)
        except JSONDecodeError:
            logging.warn("eventbase - can't decode %s" % input)
            return self
        if type(temp) != dict:
            logging.warn("eventbase - %s is not a dict" % str(temp))
            return self
        self.update(temp)
        return self

